package com.utils;

import java.security.Key;
import java.security.SecureRandom;
import java.security.Security;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

/**
 * DES security encode
 * 
 * @author tao
 *
 */
public class DESUtil {

	static {
		Security.insertProviderAt(new BouncyCastleProvider(), 1);
	}

	/**
	 * Secret Key Algorithm <br>
	 * Java 6 only support 56bit Secret Key <br>
	 * Bouncy Castle support 64bit Secret Key
	 */
	public static final String KEY_ALGORITHM = "DES";

	/**
	 * encode/decode Algorithm / Working Mode / Fill Mode
	 */
	public static final String CIPHER_ALGORITHM = "DES/ECB/PKCS5PADDING";

	/**
	 * Convert Key
	 * 
	 * @param key
	 * 
	 *            Binary Key
	 * @return Key encryption key
	 * @throws Exception
	 */
	private static Key toKey(byte[] key) throws Exception {

		// Instantiate DES key material
		DESKeySpec dks = new DESKeySpec(key);

		// Instantiated secret key factory
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);

		// Generate Secret Key
		SecretKey secretKey = keyFactory.generateSecret(dks);

		return secretKey;
	}

	/**
	 * decode
	 * 
	 * @param data
	 *            content
	 * @param key
	 *            secret key
	 * @return byte[] Decryption data
	 * @throws Exception
	 */
	public static byte[] decrypt(byte[] data, byte[] key) throws Exception {

		// Restore Key
		Key k = toKey(key);

		// Instantiation
		Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);

		// Initialize, set to decryption mode
		cipher.init(Cipher.DECRYPT_MODE, k);

		// Execute Operation
		return cipher.doFinal(data);
	}

	/**
	 * Encryption
	 * 
	 * @param data
	 *            Data to be encrypted
	 * @param key
	 *            encryption key
	 * @return byte[] Encrypt data
	 * @throws Exception
	 */
	public static byte[] encrypt(byte[] data, byte[] key) throws Exception {

		// Restore Key
		Key k = toKey(key);

		// Instantiation
		Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);

		// Initialize, set to encryption mode
		cipher.init(Cipher.ENCRYPT_MODE, k);

		// Execute Operation
		return cipher.doFinal(data);
	}

	/**
	 * Generate Key <br>
	 * Java 6 only support 56bit secret key <br>
	 * Bouncy Castle support 64bit key <br>
	 * 
	 * @return byte[] Binary Key
	 * @throws Exception
	 */
	public static byte[] initKey() throws Exception {

		/*
		 * Instantiation key generator
		 * 
		 * if want to use 64bit key, pay attention to replace follow code:
		 * "KeyGenerator.getInstance(CIPHER_ALGORITHM);" to
		 * "KeyGenerator.getInstance(CIPHER_ALGORITHM, "BC");"
		 */
		KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM);

		/*
		 * Initialize Key Generator.if want to use 64bit key, pay attention to
		 * replace follow code: "kg.init(56);" to "kg.init(64);"
		 */
		kg.init(56, new SecureRandom());

		// Generate Secret Key
		SecretKey secretKey = kg.generateKey();

		// Get the binary encoding form of the key
		return secretKey.getEncoded();
	}

	public static byte[] initKey(String seed) throws Exception {
		KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM);
		SecureRandom secureRandom = new SecureRandom(new Base64().decode(seed));
		kg.init(secureRandom);
		SecretKey secretKey = kg.generateKey();
		return secretKey.getEncoded();
	}
}
